#ifndef __M_BUF_H__
#define __M_BUF_H__
#include "util.hpp"
#include <vector>
#include <cassert>

namespace Mylog
{
    #define DEFAULT_BUFFER_SIZE (1 * 1024 * 1024)
    #define DEFAULT_THRESHOLD_SIZE (8 * 1024 * 1024)
    #define DEFAULT_INCREMENT_SIZE (1 * 1024 * 1024)

    class Buffer
    {
    public:
        Buffer(const size_t buffersize = DEFAULT_BUFFER_SIZE) : _buffer(buffersize), _writer_idx(0), _reader_idx(0)
        {
        }

        void push(const char *data, size_t len)
        {
            // 缓冲区空间不足： 阻塞或扩容
            // 1.阻塞，采用固定大小。超出范围直接返回，其他模块进行阻塞处理  
            // if (len > writeAbleSize())
            //     return;
            // 2.扩容 —— 设定阈值，未达到阈值翻倍增长；达到阈值，线性增长
            ensureEnoughSize(len);
            std::copy(data, data + len, &_buffer[_writer_idx]);
            moveWriter(len);
        }
        // 返回可读数据的起始位置
        const char *begin() { return &_buffer[_reader_idx]; }
        // 返回可读数据的长度
        size_t readAbleSize() { return _writer_idx - _reader_idx; }
        // 返回可写数据的长度
        size_t writeAbleSize() { return _buffer.size() - _writer_idx; }
        void moveReader(size_t len)
        {
            assert(len <= readAbleSize());
            _reader_idx += len;
        }
        // 重置读写位置，初始化缓冲区
        void reset() { _writer_idx = _reader_idx = 0; }
        // 对缓冲区buffer进行交换
        void swap(Buffer &buffer)
        {
            _buffer.swap(buffer._buffer);
            std::swap(_writer_idx, buffer._writer_idx);
            std::swap(_reader_idx, buffer._reader_idx);
        }
        bool empty() { return _writer_idx == _reader_idx; }

    private:
        void ensureEnoughSize(size_t len)
        {
            if (len <= writeAbleSize())
                return;
            // 扩容
            if (_buffer.size() < DEFAULT_THRESHOLD_SIZE)
                _buffer.resize(_buffer.size() * 2 + len);
            else
                _buffer.resize(_buffer.size() + DEFAULT_INCREMENT_SIZE + len);
        }
        // 读写指针向后偏移
        void moveWriter(size_t len)
        {
            assert(len + _writer_idx <= _buffer.size());
            _writer_idx += len;
        }

    private:
        std::vector<char> _buffer;
        size_t _writer_idx;
        size_t _reader_idx;
    };
}
#endif
